home *** CD-ROM | disk | FTP | other *** search
Wrap
/* Miranda Installer - Installs nightlies and Miranda addons. Copyright (C) 2002-2003 Goblineye Entertainment Authors: Saar (Tornado) and Kai (kai_b) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "MirandaInstaller.h" #pragma hdrstop HINSTANCE g_hInstance = NULL; // globally tracked hinstance HANDLE g_hWorkThread = NULL; // handle to worker thread byte g_bInstallFlags = 0; // installation flags. LSB is silent, 2 is restart when done bool g_fStopThread = false; DWORD g_dwDdeInst = 0; // global DDE instance HWND g_hInstallDlg = NULL; MAIN_OPTIONS g_WorkOptions; // guess what this is... :) HMENU g_hContextMenu = NULL; // context menu WNDPROC g_lpfListView = NULL; // listview control (subclassed for drag'n'drop) LRESULT CALLBACK LVSubClassProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_DROPFILES: { HDROP hDrop = (HDROP)wParam; char szPath[MAX_PATH + 1]; for (UINT index=0,iCount=DragQueryFile(hDrop,-1,NULL,0);index < iCount;index++) { DragQueryFile(hDrop,index,szPath,MAX_PATH+1); if (lstrlen(szPath) > 0) { DWORD dwAtts = GetFileAttributes(szPath); if (dwAtts == INVALID_FILE_ATTRIBUTES) // invalid { continue; } if (dwAtts & FILE_ATTRIBUTE_DIRECTORY) // directory { if (*(szPath+lstrlen(szPath)-1) != '\\') // no backslash { lstrcat(szPath,"\\"); // must be backslashed already } InstallList_AddDirectory(GetParent(hWnd),szPath); } else // file { InstallList_AddFile(GetParent(hWnd),szPath); } } } DragFinish(hDrop); return(0); } break; } return(CallWindowProc(g_lpfListView,hWnd,uMsg,wParam,lParam)); } void Parse_CommandLine(char *lpCmdLine) { char *lpIndex = lpCmdLine; byte bInstallType = 0; // 0 - none, 1 - file, 2 - dir bool fGotFileDir = false; byte l_bInstallFlags = 0; // goes global if we got an installation char szArgument[MAX_PATH + 1]; // maximum allowed size of an argument (this will hold the filename/directory when we're done) while ((lpIndex != NULL) && (*lpIndex != '\0')) { char *lpNext; if (*lpIndex == '\"') // if we got a double-quotes in there { lpNext = strchr(lpIndex+1,'\"'); if (lpNext) // isn't NULL, yay { lpNext++; } else // NULL, crap { bInstallType = 0; // not installing nothing break; } } else { lpNext = strchr(lpIndex,' '); } if (lpNext == NULL) { lpNext = lpIndex + lstrlen(lpIndex); // end } char *lpCopyTo = lpNext; // we copy lpCopyTo-lpIndex if (lpCopyTo-lpIndex > 512) { lpCopyTo = lpIndex + 512; } lstrcpyn(szArgument,lpIndex,lpCopyTo - lpIndex + 1); // szArgument[lpCopyTo - lpIndex] = '\0'; // NULL it (no need to, lstrcpyn does it for us) // now some checks if (lstrcmpi(szArgument,"/silent") == 0) // silent { l_bInstallFlags |= 1; } else if (lstrcmpi(szArgument,"/restart") == 0) // restart when done { l_bInstallFlags |= 2; } else if (lstrcmpi(szArgument,"/directory") == 0) { bInstallType = 2; } else if (*lpNext == '\0') // if next is NULL, we got dir/filename { if (bInstallType == 0) // if we got nothing so far { bInstallType = 1; // then it's file installation } fGotFileDir = true; } if (*lpNext == ' ') lpNext++; lpIndex = lpNext; } // now we process what we got from the command line // we require both silent and restart, or just silent if ((bInstallType) && (fGotFileDir)) // wee, we got something to install { if ((l_bInstallFlags == 0) || (l_bInstallFlags == 3) || (l_bInstallFlags == 1)) { g_bInstallFlags = l_bInstallFlags; } else // no flags { g_bInstallFlags = 0; } // check to see if we have double-quotes if ((lstrlen(szArgument) > 2) && (*szArgument == '\"') && (*(szArgument+lstrlen(szArgument)-1) == '\"')) // double-quotes on both end { for (unsigned int index=1,iLen=lstrlen(szArgument)-1;index < iLen;index++) { szArgument[index-1] = szArgument[index]; } szArgument[index-1] = '\0'; } if (bInstallType == 1) { InstallList_AddFile(g_hInstallDlg,szArgument); } else { if (*(szArgument+lstrlen(szArgument)-1) != '\\') // no backslash { lstrcat(szArgument,"\\"); // must be backslashed already } InstallList_AddDirectory(g_hInstallDlg,szArgument); } } // if g_fSilentInstall is true, then installation will be triggered here if (g_bInstallFlags & 1) { SendDlgItemMessage(g_hInstallDlg,IDOK,BM_CLICK,0,0); // get to work! =D } } // no use for this one (dummy callback, used for client) HDDEDATA CALLBACK DdeDummyCallback(UINT uType,UINT uFmt,HCONV hconv,HDDEDATA hsz1,HDDEDATA hsz2,HDDEDATA hdata,HDDEDATA dwData1,HDDEDATA dwData2) { return(FALSE); } HDDEDATA CALLBACK DdeCallback(UINT uType,UINT uFmt,HCONV hconv,HDDEDATA hsz1,HDDEDATA hsz2,HDDEDATA hdata,HDDEDATA dwData1,HDDEDATA dwData2) { switch(uType) { case XTYP_CONNECT: { // check topic char szTemp[32]; if (!DdeQueryString(g_dwDdeInst,(HSZ)hsz1,szTemp,32,CP_WINANSI)) { return(FALSE); } if (lstrcmp(szTemp,DDE_TOPIC)) { return(FALSE); } // check service if (!DdeQueryString(g_dwDdeInst,(HSZ)hsz2,szTemp,32,CP_WINANSI)) { return(FALSE); } if (lstrcmp(szTemp,DDE_SERVICE)) { return(FALSE); } return((HDDEDATA)TRUE); } break; case XTYP_POKE: { if (uFmt != CF_TEXT) // only text! { return(DDE_FNOTPROCESSED); } // check topic char szTemp[32]; if (!DdeQueryString(g_dwDdeInst,(HSZ)hsz1,szTemp,32,CP_WINANSI)) { return(DDE_FNOTPROCESSED); } if (lstrcmp(szTemp,DDE_TOPIC)) { return(DDE_FNOTPROCESSED); } // check item if (!DdeQueryString(g_dwDdeInst,(HSZ)hsz2,szTemp,32,CP_WINANSI)) { return(DDE_FNOTPROCESSED); } if (lstrcmp(szTemp,DDE_ITEM)) { return(DDE_FNOTPROCESSED); } // process data here... char *lpCmdLine = (char*)DdeAccessData(hdata,NULL); Parse_CommandLine(lpCmdLine); DdeUnaccessData(hdata); return((HDDEDATA)DDE_FACK); } break; } return(NULL); } INT_PTR CALLBACK InstallDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { g_hInstallDlg = hwndDlg; HICON hIcon = LoadIcon(g_hInstance,MAKEINTRESOURCE(IDI_DEFICON)); SendMessage(hwndDlg,WM_SETICON,ICON_SMALL,(LPARAM)hIcon); SendMessage(hwndDlg,WM_SETICON,ICON_BIG,(LPARAM)hIcon); // ownerdraw SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_TOTAL),GWL_STYLE,GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_TOTAL),GWL_STYLE) | SS_OWNERDRAW); // init some stuff HWND hProgressTotal = GetDlgItem(hwndDlg,IDC_PROGRESS_TOTAL); SetWindowLongPtr(hProgressTotal,GWLP_USERDATA,0); SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_STATIC_TOTALTOTAL),GWLP_USERDATA,0); LockWindowUpdate(hwndDlg); InvalidateRect(hProgressTotal,NULL,true); UpdateWindow(hProgressTotal); LockWindowUpdate(NULL); // done initing stuff HWND hListView = GetDlgItem(hwndDlg,IDC_INSTALLATIONS); // let's set the first column LVCOLUMN lvCol; lvCol.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; lvCol.fmt = LVCFMT_LEFT; lvCol.cx = 60; // should do the trick for (int index=0;index < 6;index++) { switch(index) { case 0: lvCol.pszText = Translate("Name"); break; case 1: lvCol.pszText = Translate("Author"); break; case 2: lvCol.pszText = Translate("Version"); break; case 3: lvCol.pszText = Translate("Type"); break; case 4: lvCol.pszText = Translate("Packages"); break; // Packages num. format is xx/yy, where xx is main packages, yy is total packages. xx might be bold (?), that'll be nice :) case 5: lvCol.pszText = Translate("Progress"); break; } lvCol.iSubItem = index; ListView_InsertColumn(hListView,index,&lvCol); } // parse the command line here // hmm parsing the command line... sounds yummy Parse_CommandLine((char*)lParam); // subclass listview control g_lpfListView = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),GWLP_WNDPROC,(LONG_PTR)LVSubClassProc); // start the DDE server. we use this funky server to receive command lines from multiple instances of mirinst // pretty cool if u ask me... DdeInitialize(&g_dwDdeInst,(PFNCALLBACK)DdeCallback,APPCLASS_STANDARD | CBF_FAIL_EXECUTES | CBF_FAIL_REQUESTS | CBF_FAIL_SELFCONNECTIONS | CBF_FAIL_ADVISES | CBF_SKIP_ALLNOTIFICATIONS,0); DdeNameService(g_dwDdeInst,DdeCreateStringHandle(g_dwDdeInst,DDE_SERVICE,CP_WINANSI),0L,DNS_REGISTER); LP_TranslateDialog(hwndDlg); return(true); } break; case WM_DRAWITEM: { // ok we ownerdraw our own little progress bar // let's have phun :P DRAWITEMSTRUCT *pDrawItem = (DRAWITEMSTRUCT*)lParam; float fRatio = 0; // percentile int iTotal = GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_STATIC_TOTALTOTAL),GWLP_USERDATA); if (iTotal == 0) // prevent a division by zero { fRatio = 0; } else { fRatio = (float)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_TOTAL),GWLP_USERDATA) / (float)iTotal; } // create the new brush... creating on-the-spot sucks, but we don't really have a choice here byte bClrProg = (byte)(fRatio * 100); HBRUSH hBrush = CreateSolidBrush(RGB(58 + bClrProg,110 + bClrProg,154 + bClrProg)); RECT rcItem; CopyMemory(&rcItem,&(pDrawItem->rcItem),sizeof(RECT)); // make a copy rcItem.right = (long)((float)(rcItem.right - rcItem.left) * fRatio); // a silly precaution FillRect(pDrawItem->hDC,&rcItem,hBrush); DeleteObject(hBrush); // add a nice frame. gray is good :) FrameRect(pDrawItem->hDC,&(pDrawItem->rcItem),(HBRUSH)GetStockObject(GRAY_BRUSH)); SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,true); return(true); } break; // msgs from thread case MIRINST_INFOMSG_STARTING: // fresh start { // needed to draw properly later SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_STATIC_TOTALTOTAL),GWLP_USERDATA,ListView_GetItemCount(GetDlgItem(hwndDlg,IDC_INSTALLATIONS))); return(true); } break; case MIRINST_INFOMSG_STARTITEM: // wParam is ID (from ListView) - starting a new installation { // make sure (argg) // tricky, but reawarding - the progress controls userdata portion is the current we have // the static text's userdata is the total // kinda stupid... HWND hListView = GetDlgItem(hwndDlg,IDC_INSTALLATIONS); ListView_SetItemText(hListView,wParam,5,Translate("Starting...")); ListView_EnsureVisible(hListView,wParam,false); return(true); } break; case MIRINST_INFOMSG_FINISHEDITEM: // wParam is ID, lParam is 2 if we canceled, lParam is 0 if everything went well, 1 if error { HWND hListView = GetDlgItem(hwndDlg,IDC_INSTALLATIONS); if (lParam == 2) { ListView_SetItemText(hListView,wParam,5,Translate("Aborted")); } else if (lParam == 0) // good! { ListView_SetItemText(hListView,wParam,5,Translate("Finished")); } else // bad! { char szPackageName[128]; char szMsg[256]; ListView_GetItemText(hListView,wParam,0,szPackageName,128); sprintf(szMsg,Translate("Error has occured when extracting %s, try redownloading it."),szPackageName); MessageBox(hwndDlg,szMsg,Translate("Miranda Installer Error"),MB_ICONWARNING); ListView_SetItemText(hListView,wParam,5,Translate("Failed")); // SetWindowLongPtr(GetDlgItem(hwndDlg,IDOK),GWLP_USERDATA,1); // error has occured } // now update total SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_TOTAL),GWLP_USERDATA,wParam+1); // got package total SendMessage(hwndDlg,WM_USER+120,0,0); // update and stuff return(true); } break; case MIRINST_INFOMSG_EXTRACTING: // extracting a file. wParam is package ID. lParam is a pointer to the file name - extraction will begin in a sec { char szLine[256]; sprintf(szLine,Translate("Extracting %s..."),(char*)lParam); ListView_SetItemText(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),wParam,5,szLine); return(true); } break; case MIRINST_INFOMSG_DONE: // the thread finished work. yippie. { WaitForSingleObject(g_hWorkThread,INFINITE); // wait for the thread to finish completely CloseHandle(g_hWorkThread); g_hWorkThread = NULL; SetDlgItemText(hwndDlg,IDOK,Translate("Start")); // LVN_DELETEITEM is working on this // EnableWindow(GetDlgItem(hwndDlg,IDOK),false); // nothing more // EnableWindow(GetDlgItem(hwndDlg,IDC_STARTMIRANDA),false); // not relevant // Sleep(1000); // the user should know what happened?... :) ahh if ((!(g_bInstallFlags & 1)) && (!wParam)) // no error, tell everything is good { MessageBox(hwndDlg,Translate("Installation is finished. Click OK to continue."),Translate("Miranda Installer"),MB_ICONINFORMATION); } // only clear after we show dialog (nicer) SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_STATIC_TOTALTOTAL),GWLP_USERDATA,0); SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_TOTAL),GWLP_USERDATA,0); SendMessage(hwndDlg,WM_USER+120,0,0); // go over list, find any language packs WORD wLangPackNum = 0; // count starts here HWND hListView = GetDlgItem(hwndDlg,IDC_INSTALLATIONS); LVITEM lvItem; lvItem.iSubItem = 0; lvItem.mask = LVIF_PARAM; for (int index=0,iCount=ListView_GetItemCount(hListView);index < iCount;index++) { lvItem.iItem = index; ListView_GetItem(hListView,&lvItem); if (((ADDON_LISTINFO*)lvItem.lParam)->bType == INSTALLTYPE_LANGUAGE) { wLangPackNum++; } } ListView_DeleteAllItems(hListView); // I salute you *sniff* if (wLangPackNum > 0) // we have langpacks from the last install { DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_SELECTLANGPACK),hwndDlg,LangPackDlgProc); } if (g_bInstallFlags & 1) // no error, then we shutdown ourselves { // okay we're done installing DestroyWindow(hwndDlg); } return(true); } break; case WM_USER+112: // change in num of items to install { EnableWindow(GetDlgItem(hwndDlg,IDOK),wParam); // nothing more return(true); } break; case WM_USER+120: // if wParam is 0, we update the percentile and do other invalidation and update to package progress, if wParam is 1, we touch the total { // there are a lot of reference to package here // package = item // it's this way coz this code like came out of the box from wassup updater HWND hProgressTotal = GetDlgItem(hwndDlg,IDC_PROGRESS_TOTAL); LockWindowUpdate(hwndDlg); InvalidateRect(hProgressTotal,NULL,true); UpdateWindow(hProgressTotal); LockWindowUpdate(NULL); int iTotal = GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_STATIC_TOTALTOTAL),GWLP_USERDATA); if (iTotal == 0) // prevent a division by zero { SetDlgItemText(hwndDlg,IDC_PROGRESS_TOTALPERCENT,"0%"); } else { char szPercentage[6]; // precaution wsprintf(szPercentage,"%d",(long)(((float)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROGRESS_TOTAL),GWLP_USERDATA) / (float)iTotal) * 100.0f)); lstrcat(szPercentage,"%"); // not taking any chances SetDlgItemText(hwndDlg,IDC_PROGRESS_TOTALPERCENT,szPercentage); } return(true); } break; case WM_COMMAND: { if (HIWORD(wParam) == BN_CLICKED) // If we clicked { switch (LOWORD(wParam)) { case ID_MAINMENU_ABOUT: { DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_ABOUTDIALOG),hwndDlg,AboutDlgProc); return(true); } break; case ID_MAINMENU_STARTMIRANDA: // start miranda { g_bInstallFlags &= ~2; // if we will have to restart miranda later, then don't Restart_Miranda(); return(true); } break; case ID_MAINMENU_INSTALLSINGLE: { // let's first ask where to save OPENFILENAME ofnStruct; char szFilename[MAX_PATH + 1]; *szFilename = '\0'; ZeroMemory(&ofnStruct,sizeof(OPENFILENAME)); ofnStruct.lStructSize = sizeof(OPENFILENAME); ofnStruct.hwndOwner = hwndDlg; char szFilter[256]; char *lpCurText = szFilter; lstrcpy(lpCurText,Translate("Addons (*.min;*.mir;*.mii;*.mis;*.mil;*.mit;*.mio;*.mic;*.mik)")); lpCurText += lstrlen(lpCurText) + 1; lstrcpy(lpCurText,"*.min;*.mir;*.mii;*.mis;*.mil;*.mit;*.mio;*.mic;*.mik"); lpCurText += lstrlen(lpCurText) + 1; // zip files lstrcpy(lpCurText,Translate("Zip Files (*.zip)")); lpCurText += lstrlen(lpCurText) + 1; lstrcpy(lpCurText,"*.zip"); lpCurText += lstrlen(lpCurText) + 1; // all files lstrcpy(lpCurText,Translate("All Files (*.*)")); lpCurText += lstrlen(lpCurText) + 1; CopyMemory(lpCurText,"*.*\0\0",5); ofnStruct.lpstrFilter = szFilter; ofnStruct.lpstrFile = szFilename; ofnStruct.lpstrDefExt = "mir"; // default extension ofnStruct.nMaxFile = MAX_PATH + 1; ofnStruct.lpstrTitle = Translate("Install file..."); ofnStruct.Flags = OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if (GetOpenFileName(&ofnStruct)) { InstallList_AddFile(hwndDlg,ofnStruct.lpstrFile); } return(true); } break; case ID_MAINMENU_INSTALLMULTI: { // more code from wassup // heh :) char szDirectory[MAX_PATH + 1]; BROWSEINFO browseInfo; ZeroMemory(&browseInfo,sizeof(BROWSEINFO)); // quicker than NULLing everything browseInfo.hwndOwner = hwndDlg; browseInfo.pszDisplayName = szDirectory; browseInfo.lpszTitle = Translate("Select directory:"); browseInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; LPITEMIDLIST idList; if (idList = SHBrowseForFolder(&browseInfo),idList != NULL) // old habit { LPMALLOC psMalloc; // [soon to be] pointer to shell's IMalloc object SHGetMalloc(&psMalloc); SHGetPathFromIDList(idList,szDirectory); psMalloc->Free(idList); // release the damn idList psMalloc->Release(); // ok now szDirectory is the directory where we're going to put our stuff if (*(szDirectory+lstrlen(szDirectory)-1) != '\\') // no backslash { lstrcat(szDirectory,"\\"); // must be backslashed already } InstallList_AddDirectory(hwndDlg,szDirectory); return(true); } return(true); } break; case ID_MAINMENU_ASSOCIATE: { // Right now, all file types share the same description // and icon. This can be changed, though. if (!RegisterApplication("MirInst","Miranda Installer")) { MessageBox(hwndDlg,Translate("Could not register application, please try again."),Translate("Miranda Installer Error"),MB_ICONWARNING); return(true); // couldn't register the app, so registering file types makes no sense } for (int index=0;INSTALLATION_EXTS_ARR[index] != NULL;index++) { char szExt[5]; // big enough wsprintf(szExt,".%s",INSTALLATION_EXTS_ARR[index]); RegisterExtension(szExt,"MirInst"); } MessageBox(hwndDlg,Translate("Association of file types was successful!"),Translate("Miranda Installer"),0); return(true); } break; case ID_MAINMENU_EXIT: { DestroyWindow(hwndDlg); return(true); } break; case ID_MAINMENU_OPTIONS: { DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_OPTIONSDIALOG),hwndDlg,OptionsDlgProc); return(true); } break; case ID_MAINMENU_LANGPACKS: { // we pop if we got any kind of langpack present // that's bcoz the option of using no langpacks is also available // then we pop nice dialog char szSearchPath[MAX_PATH + 1]; WIN32_FIND_DATA findData; wsprintf(szSearchPath,"%s\\langpack_*.txt",g_WorkOptions.szLangDirectory); HANDLE hFindFile; bool fLPAvail = false; if (hFindFile = FindFirstFile(szSearchPath,&findData), hFindFile != INVALID_HANDLE_VALUE) { fLPAvail = true; FindClose(hFindFile); } if (!fLPAvail) // try miranda's dir { wsprintf(szSearchPath,"%s\\langpack_*.txt",g_WorkOptions.szMirandaDirectory); if (hFindFile = FindFirstFile(szSearchPath,&findData), hFindFile != INVALID_HANDLE_VALUE) { do { fLPAvail = true; FindClose(hFindFile); break; } while (FindNextFile(hFindFile,&findData)); } } if (fLPAvail) // we got something { DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_SELECTLANGPACK),hwndDlg,LangPackDlgProc); } else { MessageBox(hwndDlg,Translate("There are no installed language packs to manage."),Translate("Miranda Installer"),MB_ICONINFORMATION); } return(true); } break; case IDOK: // install { if (g_hWorkThread == NULL) // not doing anything right now { // is app running HWND hwndMiranda = Is_App_Running(); // figure out if Miranda is running if (hwndMiranda != NULL) // Miranda is running { bool fKillMiranda = false; if (g_bInstallFlags & 1) // silent installation, just install the damn thing { fKillMiranda = true; } else if (!(g_WorkOptions.dwFlags & 8)) // if we didn't specify we shouldn't get warnings // ask the user { char szTitle[32]; char szMsg[512]; szTitle[GetWindowText(hwndMiranda,szTitle,32)] = '\0'; // make sure it's sealed tight wsprintf(szMsg,Translate("Miranda was found running (The window's title is \"%s\"). This might interfere with the installation. Would you like to close it?"),szTitle); if (MessageBox(hwndDlg,szMsg,Translate("Miranda Installer"),MB_ICONQUESTION | MB_YESNO) == IDYES) { fKillMiranda = true; } else { g_bInstallFlags &= ~2; // don't restart Miranda later, it's already running } } if (fKillMiranda) // kill Miranda! { // Wassup Updater code DWORD dwPID; GetWindowThreadProcessId(hwndMiranda,&dwPID); // get Miranda's PID HANDLE hMirandaProcess = OpenProcess(SYNCHRONIZE,false,dwPID); // we try to get a handle to the process (we use it to wait) // used by Miranda InstallMaker, close Miranda now // thx kai_b PostMessage(hwndMiranda,WM_COMMAND,40001,0); // posting is safer // no danger there if (hMirandaProcess != NULL) { WaitForSingleObject(hMirandaProcess,3000); // 3 secs is enough CloseHandle(hMirandaProcess); } // we let Miranda 3 seconds to close itself, that's enough if (IsWindow(hwndMiranda)) // still there { MessageBox(hwndDlg,Translate("Could not close Miranda's window, try again."),Translate("Miranda Installer Error"),MB_ICONWARNING); return(1); } g_bInstallFlags |= 2; // restart miranda later } } DWORD dwTID; SetDlgItemText(hwndDlg,IDOK,Translate("Stop!")); g_hWorkThread = CreateThread(NULL,0,InstallerProc,hwndDlg,0,&dwTID); // create the thread } else // working { g_fStopThread = true; } return(true); } break; } } } break; case WM_INITMENU: // modify menu before it is shown { bool fGrayed = g_hWorkThread != NULL; HMENU hMenu = (HMENU)wParam; if (hMenu == GetMenu(hwndDlg)) { EnableMenuItem(hMenu,ID_MAINMENU_LANGPACKS,MF_BYCOMMAND | ((fGrayed) ? (MF_GRAYED) : (MF_ENABLED))); EnableMenuItem(hMenu,ID_MAINMENU_INSTALLSINGLE,MF_BYCOMMAND | ((fGrayed) ? (MF_GRAYED) : (MF_ENABLED))); EnableMenuItem(hMenu,ID_MAINMENU_INSTALLMULTI,MF_BYCOMMAND | ((fGrayed) ? (MF_GRAYED) : (MF_ENABLED))); EnableMenuItem(hMenu,ID_MAINMENU_OPTIONS,MF_BYCOMMAND | ((fGrayed) ? (MF_GRAYED) : (MF_ENABLED))); EnableMenuItem(hMenu,ID_MAINMENU_STARTMIRANDA,MF_BYCOMMAND | ((fGrayed) ? (MF_GRAYED) : (MF_ENABLED))); // test for Miranda if (!fGrayed) // not working { MENUITEMINFO menuInfo; menuInfo.cbSize = sizeof(MENUITEMINFO); menuInfo.fMask = MIIM_STRING; if (Is_App_Running()) // currently running { menuInfo.dwTypeData = Translate("Start Miranda (Running)"); } else { menuInfo.dwTypeData = Translate("Start Miranda"); } SetMenuItemInfo(hMenu,ID_MAINMENU_STARTMIRANDA,false,&menuInfo); } } return(0); } break; case WM_NOTIFY: // Notification messages { switch(((LPNMHDR)lParam)->code) { case LVN_KEYDOWN: // del button { if (g_hWorkThread == NULL) { NMLVKEYDOWN *pKeyDown = (NMLVKEYDOWN*)lParam; if (pKeyDown->wVKey == VK_DELETE) { HWND hListView = GetDlgItem(hwndDlg,IDC_INSTALLATIONS); int iItem = ListView_GetSelectionMark(hListView); if ((iItem != -1) && (ListView_GetSelectedCount(hListView) > 0)) { ListView_DeleteItem(hListView,iItem); } } } } break; case NM_RCLICK: { if ((g_hWorkThread == NULL) && (g_hContextMenu != NULL)) { LVHITTESTINFO hitTest; GetCursorPos(&hitTest.pt); // don't use the message info, it could be unavail previous to 4.71 ScreenToClient(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),&hitTest.pt); int iItem = ListView_HitTest(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),&hitTest); if ((iItem != -1) && (hitTest.flags & LVHT_ONITEM)) // on label+icon { // switch to screen coords again ClientToScreen(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),&hitTest.pt); if (TrackPopupMenu(g_hContextMenu,TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,hitTest.pt.x,hitTest.pt.y,0,hwndDlg,NULL) == 1) { // delete item ListView_DeleteItem(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),iItem); } } } return(0); } break; case LVN_DELETEITEM: { // an item is about to be deleted // we must free it! NMLISTVIEW *nmLV = (NMLISTVIEW*)lParam; // we first need to get the lParam LVITEM lvItem; lvItem.mask = LVIF_PARAM; lvItem.iItem = nmLV->iItem; ListView_GetItem(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),&lvItem); ADDON_LISTINFO *node = (ADDON_LISTINFO*)lvItem.lParam; if (node != NULL) { if (node->lpFilePath != NULL) { delete [] node->lpFilePath; } delete node; // delete the bastard } if (ListView_GetItemCount(GetDlgItem(hwndDlg,IDC_INSTALLATIONS)) == 1) // last one { EnableWindow(GetDlgItem(hwndDlg,IDOK),false); // nothing more } } break; } } break; case WM_CLOSE: // block close { /* if (g_hWorkThread != NULL) // if working, don't leave { return(true); }*/ DestroyWindow(hwndDlg); } break; case WM_DESTROY: { g_hInstallDlg = NULL; if (g_dwDdeInst) { DdeNameService(g_dwDdeInst,DdeCreateStringHandle(g_dwDdeInst,DDE_SERVICE,CP_WINANSI),0L,DNS_UNREGISTER); DdeUninitialize(g_dwDdeInst); } SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),GWLP_WNDPROC,(LONG_PTR)g_lpfListView); PostQuitMessage(0); return(false); } break; } return(false); } // WINMAIN //////////////////////////////////////////////// int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE hprevinstance,LPSTR lpcmdline,int ncmdshow) {/* #ifndef NDEBUG int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Get current flag flag |= _CRTDBG_LEAK_CHECK_DF; // Turn on leak-checking bit _CrtSetDbgFlag(flag); // Set flag to the new value #endif*/ MSG msg; // Save the instance g_hInstance = hinstance; HANDLE hMutex = CreateMutex(NULL,true,"MirInst56ERD"); if (GetLastError() == ERROR_ALREADY_EXISTS) // the mutex already exists { // start session with server, send command line DWORD dwInst = 0; if (DdeInitialize(&dwInst,(PFNCALLBACK)DdeDummyCallback,APPCMD_CLIENTONLY | APPCLASS_STANDARD | CBF_SKIP_ALLNOTIFICATIONS,0) == DMLERR_NO_ERROR) { HCONV hConv = DdeConnect(dwInst,DdeCreateStringHandle(dwInst,DDE_SERVICE,CP_WINANSI),DdeCreateStringHandle(dwInst,DDE_TOPIC,CP_WINANSI),NULL); if (hConv == 0L) // can't connect to DDE server { DdeUninitialize(dwInst); return(0); } DWORD dwResult = 0; if (!DdeClientTransaction((BYTE*)lpcmdline,lstrlen(lpcmdline)+1,hConv,DdeCreateStringHandle(dwInst,DDE_ITEM,CP_WINANSI),CF_TEXT,XTYP_POKE,5000,&dwResult)) { DdeUninitialize(dwInst); return(0); } DdeUninitialize(dwInst); } CloseHandle(hMutex); // explicitly release the handle return(0); } ReleaseMutex(hMutex); CoInitialize(NULL); InitCommonControls(); PackageSelector_Init(); LP_Init(); // ok other stuff now // no point in using a template for the popup menu, maybe if/when it'll get bigger :) g_hContextMenu = CreatePopupMenu(); if (g_hContextMenu != NULL) { // the first item will be added with the [messy] InsertMenuItem, which gives us some more styles we need MENUITEMINFO menuItem; menuItem.cbSize = sizeof(MENUITEMINFO); menuItem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; menuItem.fType = MFT_STRING; menuItem.dwTypeData = Translate("Delete from list"); menuItem.cch = lstrlen((char*)menuItem.dwTypeData); menuItem.wID = 1; menuItem.fState = MFS_DEFAULT; InsertMenuItem(g_hContextMenu,1,false,&menuItem); } // settings are loaded here // build the directory char szCDir[MAX_PATH + 1]; GetModuleFileName(NULL,szCDir,MAX_PATH + 1); *(strrchr(szCDir,'\\')+1) = '\0'; lstrcat(szCDir,"Options.dat"); FILE *hFile = fopen(szCDir,"rb"); ZeroMemory(&g_WorkOptions,sizeof(g_WorkOptions)); if (hFile != NULL) { fread((void*)&g_WorkOptions,sizeof(g_WorkOptions),1,hFile); fclose(hFile); } if (lstrlen(g_WorkOptions.szMirandaDirectory) == 0) // no good, give notice, then launch options dialog { MessageBox(NULL,Translate("Before you could use Miranda Installer, you will need to set a few settings"),Translate("Miranda Installer"),MB_ICONINFORMATION); DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_OPTIONSDIALOG),NULL,OptionsDlgProc); } // main dialog CreateDialogParam(g_hInstance,MAKEINTRESOURCE(IDD_INSTALLDIALOG),NULL,InstallDlgProc,(LPARAM)lpcmdline); // enter main event loop // using better structure BOOL bRet; while ((bRet = GetMessage(&msg,NULL,0,0)) != 0) { if (bRet == -1) { break; // leave } else { TranslateMessage(&msg); DispatchMessage(&msg); } } // save settings // using szCDir found before hFile = fopen(szCDir,"wb"); if (hFile != NULL) { fwrite((void*)&g_WorkOptions,sizeof(g_WorkOptions),1,hFile); fclose(hFile); } if (g_hContextMenu != NULL) { DestroyMenu(g_hContextMenu); } LP_UnInit(); CoUninitialize(); CloseHandle(hMutex); // good practice if (g_bInstallFlags & 2) // yay, restart { Restart_Miranda(); } return(msg.wParam); }